package net.acoder.dz.transmit;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

public class Main {
    private Socket           ivr, server;
    private File             file = new File(".log");
    private String           ivrHost, serverHost;
    private int              ivrPort, serverPort;
    private FileOutputStream fos;
    private MyStream         ivrStream;
    private MyStream         fileStream;
    private MyStream         serverStream;

    public static void main(String[] args) throws Exception {
        // ServerTest.main(args);

        Main main = new Main();
        main.ivrHost = main.serverHost = "127.0.0.1";
        main.ivrPort = 23456;
        main.serverPort = 34567;
        main.init();
        Thread.sleep(20000);
        main.stop();
    }

    public void stop() {
        ivrStream.stop();
        serverStream.stop();

        try {
            ivr.close();
            server.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        fileStream.stop();
    }

    public Main() {
    }

    public void init() {
        ivrStream = new MyStream() {
            {
                name = "ivr";
            }

            @Override
            public InputStream getInputStream() {
                return Main.this.getIvrInputStream();
            }

            @Override
            public OutputStream getOutputStream() {
                return Main.this.getIvrOutputStream();
            }
        };

        serverStream = new MyStream() {
            {
                name = "server";
            }

            @Override
            public InputStream getInputStream() {
                return Main.this.getServerInputStream();
            }

            @Override
            public OutputStream getOutputStream() {
                return Main.this.getServerOutputStream();
            }
        };

        fileStream = new MyStream() {
            {
                name = "file";
            }

            @Override
            public void stop() {
                try {
                    this.getOutputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void run() {
                startWrite();
            }

            @Override
            public InputStream getInputStream() {
                return null;
            }

            @Override
            public OutputStream getOutputStream() {
                if (fos == null) {
                    try {
                        if (!file.exists()) {
                            file.createNewFile();
                        }
                        fos = new FileOutputStream(file, true);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return fos;
            }

            public void startWrite() {
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            while (running) {
                                byte[] bs = inQueue.poll();
                                if (bs != null && bs.length > 0) {
                                    getOutputStream().write(bs);
                                    // System.out.println("in: "
                                    // + Arrays.toString(bs));
                                    getOutputStream().flush();
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        };

        Queue<byte[]> ivrCommand = new LinkedBlockingQueue<byte[]>();
        Queue<byte[]> serverCommand = new LinkedBlockingQueue<byte[]>();
        Queue<byte[]> fileCommand = new LinkedBlockingQueue<byte[]>();

        ivrStream.addOutQueue(serverCommand);//
        ivrStream.addOutQueue(fileCommand);
        ivrStream.setStoreQueue(ivrCommand);

        serverStream.addOutQueue(ivrCommand);
        serverStream.addOutQueue(fileCommand);
        serverStream.setStoreQueue(serverCommand);

        fileStream.setStoreQueue(fileCommand);

        new Thread(ivrStream).start();
        new Thread(serverStream).start();
        new Thread(fileStream).start();
    }

    public synchronized void connectIvr() throws Exception {
        try {
            if (ivr == null || ivr.isClosed()) {
                System.out.println(Thread.currentThread() + "connecting... "
                        + ivrHost + ":" + ivrPort);
                ivr = new Socket(ivrHost, ivrPort);
                System.out.println(Thread.currentThread() + "connected "
                        + ivrHost + ":" + ivrPort);
            }
        } catch (Exception e) {
            Thread.sleep(3000);
            e.printStackTrace();
            connectIvr();
        }
    }

    public synchronized void connectServer() throws Exception {
        try {
            if (server == null || server.isClosed()) {
                System.out.println(Thread.currentThread() + "connecting... "
                        + serverHost + ":" + serverPort);
                server = new Socket(serverHost, serverPort);
                System.out.println(Thread.currentThread() + "connected "
                        + serverHost + ":" + serverPort);
            }
        } catch (Exception e) {
            Thread.sleep(3000);
            connectServer();
        }
    }

    public synchronized InputStream getIvrInputStream() {
        try {
            if (ivr == null || ivr.isClosed()) {
                connectIvr();
            }
            return ivr.getInputStream();
        } catch (Exception e) {
            return getIvrInputStream();
        }
    }

    public synchronized OutputStream getIvrOutputStream() {
        try {
            if (ivr == null || ivr.isClosed()) {
                connectIvr();
            }
            return ivr.getOutputStream();
        } catch (Exception e) {
            return getIvrOutputStream();
        }
    }

    public synchronized InputStream getServerInputStream() {
        try {
            if (server == null || server.isClosed()) {
                connectServer();
            }
            return server.getInputStream();
        } catch (Exception e) {
            return getServerInputStream();
        }
    }

    public synchronized OutputStream getServerOutputStream() {
        try {
            if (server == null || server.isClosed()) {
                connectServer();
            }
            return server.getOutputStream();
        } catch (Exception e) {
            return getServerOutputStream();
        }
    }
}
